package laberinto;

import interfaces.IObjetoComible;
import interfaces.IPacman;

import java.util.ArrayList;

import utilidades.Constantes;
import utilidades.Random;
import utilidades.Vector;

public class Casilla{
	
	private String idCasilla;
	private int fila;
	private int columna;
	
	private Casilla casillaIzquierda;
	private Casilla casillaDerecha;
	private Casilla casillaArriba;
	private Casilla casillaAbajo;
	
	private ArrayList<IObjetoComible> contenido;

	public Casilla() {
		contenido = new ArrayList<IObjetoComible>();
		inicializarCasillasDeAlrededor();
	}
	
	protected void inicializarCasillasDeAlrededor(){
		this.casillaIzquierda = new NullCasilla();
		this.casillaDerecha = new NullCasilla();
		this.casillaArriba = new NullCasilla();
		this.casillaAbajo = new NullCasilla();
	}
	
	public Casilla(String idCasilla, String strFila, String strColumna) {
		this.idCasilla = idCasilla;
		this.fila = Integer.parseInt(strFila);
		this.columna = Integer.parseInt(strColumna);
		
		inicializarCasillasDeAlrededor();
		
		this.contenido = new ArrayList<IObjetoComible>();
	}

	// obtiene las direcciones en las que puede moverse un elemento situado en esta casilla
	public ArrayList<Vector> obtenerDireccionesPosibles(){
		ArrayList<Vector> direccionesPosibles = new ArrayList<Vector>();
		
		agregarSiEsOcupable(casillaArriba,direccionesPosibles,new Vector(0,1));
		agregarSiEsOcupable(casillaAbajo,direccionesPosibles,new Vector(0,-1));
		agregarSiEsOcupable(casillaDerecha,direccionesPosibles,new Vector(1,0));
		agregarSiEsOcupable(casillaIzquierda,direccionesPosibles,new Vector(-1,0));

		return direccionesPosibles;
	}
	
	private void agregarSiEsOcupable(Casilla casilla, ArrayList<Vector> vector,Vector dir){
		if(casilla.esOcupable())
			vector.add(dir);
	}
	
	public boolean esOcupable(){
		return true;
	}
	
	public void establecerFila(int fila){
		this.fila = fila;
	}
	
	public void establecerColumna(int columna){
		this.columna = columna;
	}
	
	public int obtenerFila(){
		return this.fila;
	}
	
	public int obtenerColumna(){
		return this.columna;
	}
	
	public int distancia(Casilla otraCasilla){
		int distanciaVertical = Math.abs(otraCasilla.obtenerColumna() - this.columna);
		int distanciaHorizontal = Math.abs(otraCasilla.obtenerFila() - this.fila);
		return distanciaVertical + distanciaHorizontal;
	}
	
	public void sacarContenido(IObjetoComible oComible) {
		this.contenido.remove(oComible);		
	}
	
	public void agregarContenido(IObjetoComible oComible) {
		this.contenido.add(oComible);		
	}

	public String obtenerBolitaBolon(){
		if (contenido.size() != 0)
			return contenido.get(0).converitEnString();
		return "";
	} 

	public boolean tieneComibles(){
		return !contenido.isEmpty();
	}
	
	public ArrayList<IObjetoComible> obtenerComibles(){
		return contenido;	
	}
	
	public Casilla obtenerIzquierda() {
		return this.casillaIzquierda;
	}

	public Casilla obtenerDerecha() {
		return this.casillaDerecha;
	}

	public Casilla obtenerArriba() {
		return this.casillaArriba;
	}

	public Casilla obtenerAbajo() {
		return this.casillaAbajo;	
	}

	
	public void setearIzquierda(Casilla otraCasilla) {
		this.casillaIzquierda = otraCasilla;
	}

	public void setearDerecha(Casilla otraCasilla) {
		this.casillaDerecha = otraCasilla;
	}

	public void setearArriba(Casilla otraCasilla) {
		this.casillaArriba = otraCasilla;
	}

	public void setearAbajo(Casilla otraCasilla) {
		this.casillaAbajo = otraCasilla;	
	}

	public String obtenerIdCasilla() {
		return this.idCasilla;
	}
	
	public void interaccionDeComiblesCon(IPacman pacman){
		for (int i=0 ;i<contenido.size(); i++){
			contenido.get(i).interactuarCon(pacman);
		}		
	}

	public boolean esBifurcacion() {
		int caminosPosibles = 0;
		
		if(casillaIzquierda != null)
			caminosPosibles++;

		if(casillaDerecha != null)
			caminosPosibles++;

		if(casillaArriba != null)
			caminosPosibles++;
	
		if(casillaAbajo != null)
			caminosPosibles++;

		if(caminosPosibles > 2)
			return true;
		
		return false;
	}

	public Vector obtenerDireccionAlAzar(Vector direccionAEvitar){
		ArrayList<Vector> direccionesPosibles = this.obtenerDireccionesPosibles();

		int cantidadDeDireccionesPosibles = direccionesPosibles.size();
		
		if (cantidadDeDireccionesPosibles == 0){
			return Constantes.NULO;
		}
		if (cantidadDeDireccionesPosibles == 1){
			return direccionesPosibles.get(0);
		}
		
		Vector direccionElegida = new Vector();
		do{
			int direccionAlAzar = Random.randInt(cantidadDeDireccionesPosibles-1);
			direccionElegida = direccionesPosibles.get(direccionAlAzar);
		}while(direccionElegida.esIgualA(direccionAEvitar));
		
		return direccionElegida;
	}
	
	public Casilla obtenerDestino(Vector direccion){

		if(direccion.esIgualA(Constantes.NULO))
			return new NullCasilla();

		if(direccion.esIgualA(Constantes.ARRIBA))
			return obtenerArriba();
		if(direccion.esIgualA(Constantes.ABAJO))
			return obtenerAbajo();
		if(direccion.esIgualA(Constantes.IZQUIERDA))
			return obtenerIzquierda();
		if(direccion.esIgualA(Constantes.DERECHA))
			return obtenerDerecha();
		
		return new NullCasilla();
	}

	public Vector obtenerPosicion() {
		return new Vector(fila,columna);
	}
}
